import React, { SyntheticEvent, useCallback, useEffect, useState } from "react";

import "./index.scss";

type ActionBtn = {
  name: string;
  callback: (item: any, index: number) => void;
};

interface IProps {
  arr: Record<string, any>[];
  caption?: string;
  width?: number;
  formatters?: Record<string, (key: string, item: any) => any>;
  sortables?: string[];
  pageSize?: number;
  ref?: any;
  showActionColumn?: boolean;
  showSelection?: boolean;
  actionBtns?: ActionBtn[];
  onSelectedItemsChanged?: (items: Set<Record<string, any>>) => void;
}

enum SpecialColumn {
  COL_SELECTION = "COL_SELECTION",
  COL_ACTIONS = "COL_ACTIONS",
}

const defaultActionBtns = [
  {
    name: "删除",
    callback: (item: any, index: number) => console.log("删除", index, item),
  },
  {
    name: "编辑",
    callback: (item: any, index: number) => console.log("编辑", index, item),
  },
  {
    name: "详情",
    callback: (item: any, index: number) => console.log("详情", index, item),
  },
];

const StoTable2: React.FC<IProps> = React.forwardRef(
  (
    {
      arr,
      caption,
      width,
      formatters,
      sortables,
      pageSize = 10,
      showSelection = true,
      showActionColumn: showActions = true,
      actionBtns = defaultActionBtns,
      onSelectedItemsChanged,
    },
    ref
  ) => {
    /* ========== START ========== */

    const [asc, setAsc] = useState(true);

    const [currentPage, setCurrentPage] = useState(1);

    const [data, setData] = useState(
      arr.slice((currentPage - 1) * pageSize, currentPage * pageSize)
    );

    const [cols, setCols] = useState(Object.keys(data[0]));

    const [selectedItems, setSelectedItems] = useState<
      Set<Record<string, any>>
    >(new Set());

    const sortDataByKey = useCallback(
      (key: string) => {
        if (sortables?.includes(key)) {
          console.log("asc=", asc);
          setAsc(!asc);

          arr = arr.sort((a, b) => {
            if (asc) {
              return Number(a[key] > b[key]) ? 1 : -1;
            } else {
              return Number(a[key] > b[key]) ? -1 : 1;
            }
          });

          setData([
            ...arr.slice((currentPage - 1) * pageSize, currentPage * pageSize),
          ]);
        }
      },
      [asc, currentPage, arr]
    );

    const updateData = () => {
      console.log("updateData!");
      setData([
        ...arr.slice((currentPage - 1) * pageSize, currentPage * pageSize),
      ]);
    };

    useEffect(() => {
      console.log("arr/currentPage changed!", arr, currentPage);
      updateData();
    }, [arr, currentPage]);

    useEffect(() => {
      console.log("STO：data changed!", data);
    }, [data]);

    const turnToPage = (page: number) => {
      console.log("turnToPage", page);
      setCurrentPage(page);
    };

    // 在组件内部定义暴露的API方法
    const doSomething = () => {
      console.log("Doing something...");
      // 执行一些操作
    };

    // 将暴露的API方法附加到ref上
    React.useImperativeHandle(ref, () => ({
      doSomething,
      turnToPage,
    }));

    /* 组件挂载 */
    useEffect(() => {
      if (showSelection && !cols.includes(SpecialColumn.COL_SELECTION)) {
        cols.unshift(SpecialColumn.COL_SELECTION);
      }

      if (showActions && !cols.includes(SpecialColumn.COL_ACTIONS)) {
        cols.push(SpecialColumn.COL_ACTIONS);
      }
    }, []);

    const onAllSelectChanged = (checked: boolean) => {
      if (checked) {
        setSelectedItems(new Set(data));
      } else {
        setSelectedItems(new Set());
      }
    };

    const onItemSelectChanged = (
      checked: boolean,
      index: number,
      item: Record<string, any>
    ) => {
      if (checked) {
        selectedItems.add(item);
      } else {
        selectedItems.delete(item);
      }
      setSelectedItems(new Set(selectedItems));
    };

    useEffect(() => {
      onSelectedItemsChanged && onSelectedItemsChanged(selectedItems);
    }, [selectedItems]);

    const getThead = (key: string, index: number) => {
      if (key === SpecialColumn.COL_SELECTION) {
        return (
          <th className="selection" key={index}>
            <input
              onChange={(e) => onAllSelectChanged(e.target.checked)}
              checked={selectedItems.size === pageSize}
              type="checkbox"
            />
          </th>
        );
      }

      if (key === SpecialColumn.COL_ACTIONS) {
        return (
          <th className="actions" key={index}>
            actions
          </th>
        );
      }

      return (
        <th
          className={key === "id" ? "id-col" : ""}
          key={index}
          onClick={() => sortDataByKey(key)}
        >
          {key}
        </th>
      );
    };

    const getTdcell = (
      key: string,
      index: number,
      item: Record<string, any>
    ) => {
      if (key === SpecialColumn.COL_SELECTION) {
        return (
          <td className="selection" key={key}>
            <input
              onChange={(e) =>
                onItemSelectChanged(e.target.checked, index, item)
              }
              checked={selectedItems.has(item)}
              type="checkbox"
            />
          </td>
        );
      }

      if (key === SpecialColumn.COL_ACTIONS) {
        return (
          <td className="actions" key={key}>
            {/* <button>删除</button>
            <button>编辑</button>
            <button>详情</button> */}
            {actionBtns.map(({ name, callback }) => (
              <button key={name} onClick={() => callback(item, index)}>
                {name}
              </button>
            ))}
          </td>
        );
      }

      return (
        <td key={index}>
          {formatters && formatters[key]
            ? formatters[key](key, item)
            : item![key]}
        </td>
      );
    };

    return (
      <div className="sto-table-box">
        {/* left */}
        <div className="left">
          <table>
            {caption && <caption>{caption}</caption>}

            <thead>
              <tr>
                {cols.slice(0, 2).map((key, index) => getThead(key, index))}
              </tr>
            </thead>

            <tbody>
              {data.map((item, index) => (
                <tr key={item.id}>
                  {showSelection &&
                    getTdcell(SpecialColumn.COL_SELECTION, index, item)}
                  {Object.keys(item)
                    .slice(0, 1)
                    .map((key, i) => getTdcell(key, i, item))}
                </tr>
              ))}
            </tbody>
          </table>
        </div>

        {/* middle */}
        <div
          className="sto-table-root"
          style={{ width: `${width ? width + "px" : "100%"}`, height: "100%" }}
        >
          <div className="table-wrapper">
            <table>
              {caption && <caption>{caption}</caption>}

              <thead>
                <tr>
                  {cols.slice(2, -1).map((key, index) => getThead(key, index))}
                </tr>
              </thead>

              <tbody>
                {data.map((item) => (
                  <tr key={item.id}>
                    {/* {showSelection && getTdcell(SpecialColumn.COL_SELECTION)} */}
                    {Object.keys(item)
                      .slice(1)
                      .map((key, i) => getTdcell(key, i, item))}
                    {/* {showActions && getTdcell(SpecialColumn.COL_ACTIONS)} */}
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>

        {/* right */}
        <div className="right">
          <table>
            {caption && <caption>{caption}</caption>}

            <thead>
              <tr>
                {cols.slice(-1).map((key, index) => getThead(key, index))}
              </tr>
            </thead>

            <tbody>
              {data.map((item, index) => (
                <tr key={item.id}>
                  {showActions &&
                    getTdcell(SpecialColumn.COL_ACTIONS, index, item)}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    );

    /* ========== END ========== */
  }
);

export default StoTable2;
